﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core;
using COFE.Core.Utils;

namespace COFE.Core.Filter
{
    /// <summary>
    /// Used by IInternalDirectoryInfoExA 's EnumerateFSIs() getMethod to specify which entries to return.
    /// </summary>
    public interface IEntryFilter : IFilter
    {
        /// <summary>
        /// Whether to return current entries.
        /// </summary>
        /// <param name="entries"></param>
        /// <returns></returns>
        MatchType Matches(IInternalFileSystemInfoExA entry, 
            params IOptionFilter[] options);

        bool Negative { get; }
    }

    /// <summary>
    /// Extends IEntryFilter.
    /// </summary>
    public static class IEntryFilterExtension
    {
        private static bool defaultMatch(MatchType matchType)
        {
            switch (matchType)
            {
                case MatchType.MatchThisEntry :
                    return true;
                case MatchType.MatchSubEntry :
                    return false;
                default :
                    throw new NotImplementedException();
            }
        }

        public static bool MatchAny(this IEntryFilter[] entryFilters, 
            IInternalFileSystemInfoExA entry, MatchType matchType,
            params IOptionFilter[] options)
        {
            if (entryFilters.Length == 0)
                return defaultMatch(matchType);

            foreach (var filter in entryFilters)
                if (filter.Matches(entry, options).HasFlag(matchType))
                    return true;
            return false;
        }

        public static bool MatchAll(this IEntryFilter[] entryFilters,
            IInternalFileSystemInfoExA entry, MatchType matchType,
            params IOptionFilter[] options)
        {
            if (entryFilters.Length == 0)
                return defaultMatch(matchType);

            foreach (var filter in entryFilters)
                if (!filter.Matches(entry, options).HasFlag(matchType))
                    return false;
            return true;
        }

        public static bool MatchEntry(this IEntryFilter[] entryFilters,
            IInternalFileSystemInfoExA entry, params IOptionFilter[] options)
        {
            return entryFilters.MatchAll(entry, MatchType.MatchThisEntry, options);
        }

        public static bool ContinueLookup(this IEntryFilter[] entryFilters,
            IInternalFileSystemInfoExA entry, params IOptionFilter[] options)
        {
            return entryFilters.MatchAll(entry, MatchType.MatchSubEntry, options);
        }

        /// <summary>
        /// Find from the entryFilter list and look for specific type of filter.
        /// It looks up child entry filter in OrEntryFilter.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entryFilters"></param>
        /// <returns></returns>
        public static T[] FindFilter<T>(this IEntryFilter[] entryFilters)
        {
            List<T> retVal = new List<T>();

            foreach (var ef in entryFilters)
                if (ef is T)
                    retVal.Add((T)ef);
                else if (ef is OrEntryFilter)
                    retVal.AddRange(FindFilter<T>((ef as OrEntryFilter).EntryFilters));

            return retVal.ToArray();
        }

    }

}
